%==========================================================================
%=  This file is part of the Sound Restoration Project
%=  (c) Copyright Industrial Mathematics Institute
%=                University of South Carolina, Department of Mathematics
%=  ALL RIGHTS RESERVED
%=
%=  Author: Borislav Karaivanov
%==========================================================================

%==========================================================================
% List of the files on which this procedure depends:
%
% none
%
%==========================================================================

%==========================================================================
% The function "combineSignals" takes a collection of consecutive signals
% of the same length and known amount of overlap between every two
% adjacent, and combines them into a single signal accounting for their
% overlaps.
% INPUT: "allSignalsArr" is a an a 2D array whose columns hold the
% individual signals to be combined.
% "overlapArr" is a 1D array holding the amount of overlap (measured in
% number of samples) between every two consecutive signals. Its length is
% one less than the number of all given signals.
% "waitbarStruct" is an optional parameter specifying a structure of
% parameters used to set a waitbar. Those parameters are a waitbar handle,
% a starting position on the waitbar (a number between 0 and 1), a relative
% length along the waitbar (a number between 0 and (1 - starting position),
% an initial value for a counter that counts the events whose progress is
% being illustrated by the waitbar, and a total reflecting the total number
% of events of the said kind.
% OUTPUT: "signalArr" is column vector returning the single signal
% combining all given signals.
%==========================================================================
function signalArr = combineSignals(allSignalsArr, overlapArr, waitbarStruct)

% Get the number of signals and their common length.
[signalLength, numSignals] = size(allSignalsArr);

% Allocate memory for a single signal combining all individual signals.
signalArr = zeros(signalLength*numSignals - sum(overlapArr), 1);

% Store the nonoverlapped portion of the first signal.
if isempty(overlapArr)
    signalArr = allSignalsArr(:, 1);
    return;
end
lastUsed = signalLength - overlapArr(1);
signalArr(1:lastUsed) = allSignalsArr(1:lastUsed, 1);
% Combine the individual signals into a single signal.
for k = 1:(numSignals - 2)
    
    % Calculate the combined signal over the overlapping portion of the
    % previous and the current signals as a weighted average of the two
    % overlapping signals. For weights use the increasing portion of the
    % Tukey window function with parameter r = 1 (the same as the Hann
    % window function).
    overlap = overlapArr(k);
    nextLastUsed = lastUsed + overlap;
    r = 1; % for linear weights use r = 0
    weightArr = tukeywin(2*overlap - 1, r);
    weightArr = weightArr(1:overlap);
    signalArr((lastUsed + 1):nextLastUsed) = ...
        allSignalsArr((end - overlap + 1):end, k).*weightArr(end:-1:1) + ...
        allSignalsArr(1:overlap, k + 1).*weightArr;
    lastUsed = nextLastUsed;
    
    % Store the nonoverlapped portion of the current signal.
    nextLastUsed = lastUsed + signalLength - overlap - overlapArr(k + 1);
    signalArr((lastUsed + 1):nextLastUsed) = ...
        allSignalsArr((overlap + 1):(end - overlapArr(k + 1)), k + 1);
    lastUsed = nextLastUsed;
   
    % Update the progress bar.
    if (exist('waitbarStruct', 'var') == 1)
        if getappdata(waitbarStruct.handle, 'canceling')
            return;
        end
        if (waitbarStruct.total == 0)
            waitbarStruct.total = numSignals - 2;
        end
        waitbar(waitbarStruct.start + (waitbarStruct.length)*(k/(numSignals - 2)), ...
            waitbarStruct.handle, sprintf('Step %d of %d: adding signal %d out of %d to audio', ...
            waitbarStruct.index, waitbarStruct.totalIndices, ...
            waitbarStruct.first + k - 1, waitbarStruct.total));
    end
end

% Calculate the combined signal over the overlapping portion of the second
% to last and the last signals as a weighted average of the two overlapping
% signals. For weights use the increasing portion of the Tukey window
% function with parameter r = 1 (the same as the Hann window function).
overlap = overlapArr(end);
nextLastUsed = lastUsed + overlap;
r = 1; % for linear weights use r = 0
weightArr = tukeywin(2*overlap - 1, r);
weightArr = weightArr(1:overlap);
signalArr((lastUsed + 1):nextLastUsed) = ...
    allSignalsArr((end - overlap + 1):end, end - 1).*weightArr(end:-1:1) + ...
    allSignalsArr(1:overlap, end).*weightArr;
lastUsed = nextLastUsed;

% Store the nonoverlapped portion of the last signal.
signalArr((lastUsed + 1):(lastUsed + signalLength - overlap)) = ...
    allSignalsArr((overlap + 1):end, end);

return;
% end of the function "combineSignals"
